#region "Copyright (C) Lenny Granovsky. 2005-2013"
//This program is free software distribute under the terms of the GNU General Public License as published by
//the Free Software Foundation. Please read AssemblyInfo.cs file for more information.
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Reflection;
using System.IO;

namespace Web.Enhancements.Rest
{
    [Serializable()]
    internal class WebRestHandlerFactory : CallingTargetFactory, IHttpHandlerFactory
    {
        WebRestHandlerCollection handlersToRunNoSession;
        WebRestHandlerCollection handlersToRunWithSession;
        WebRestHandlerCollection handlersToRunWithReadOnlySession;

        public WebRestHandlerFactory()
        {
            this.handlersToRunNoSession = new WebRestHandlerCollection(System.Web.SessionState.SessionStateBehavior.Disabled);
            this.handlersToRunWithSession = new WebRestHandlerCollection(System.Web.SessionState.SessionStateBehavior.Required);
            this.handlersToRunWithReadOnlySession = new WebRestHandlerCollection(System.Web.SessionState.SessionStateBehavior.ReadOnly);
        }

        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
#if ENABLE_TIMING
                System.Diagnostics.Stopwatch watch = null;
#endif
            try
            {
#if ENABLE_TIMING
                watch = new System.Diagnostics.Stopwatch();
                watch.Start();
                context.Items.Add("WebRestMainTimer", watch);
#endif
#if ENABLE_TIMING || TRACE
                System.Diagnostics.Trace.WriteLine(string.Format("WebRest handler factory started at {0} for {1}.", DateTime.Now.ToString(), context.Request.RawUrl));
#endif
                object target = base.CreateInvocationContext(context.Request.AppRelativeCurrentExecutionFilePath, context.Request.QueryString.ToString(), context.Request.HttpMethod);
                context.Items.Add("WebRestHanlerInvocationTarget", target);

                //call Filters before handler created
                foreach (Filters.IWebRestFilter filter in WebRestServiceContext.Current.Filters)
                {
#if TRACE
                    System.Diagnostics.Trace.WriteLine(string.Format("Calling {0} REST filter before the service handler created.", filter.GetType().FullName));
#endif
                    filter.BeforeHandlerCreated(context, WebRestServiceContext.Current);
                    if (WebRestServiceContext.Current.Cancel)
                        break;//request will be cancelled upon handler start
                }

                switch (WebRestServiceContext.Current.SessionMode)
                {
                    case System.Web.SessionState.SessionStateBehavior.Required:
                        return this.handlersToRunWithSession.GetHandler();
                    case System.Web.SessionState.SessionStateBehavior.ReadOnly:
                        return this.handlersToRunWithReadOnlySession.GetHandler();
                    default:
                        return this.handlersToRunNoSession.GetHandler();
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                throw;
            }
            catch (Exception e)
            {
#if TRACE
                System.Diagnostics.Trace.WriteLine(string.Format("WebRest handler factory thrown an exception. Error: {0}", e.ToString()));
#endif
                throw;
            }
            finally
            {
#if ENABLE_TIMING
                System.Diagnostics.Trace.WriteLine(string.Format("WebRest handler factory ended - {0} ticks elapsed.", watch.ElapsedTicks.ToString()));
#endif
            }
        }

        public void ReleaseHandler(IHttpHandler handler)
        {
            if (handler.IsReusable)
            {
                if (handler.GetType().GetInterface("System.Web.SessionState.IRequiresSessionState") != null)
                {
                    if (handler.GetType().GetInterface("System.Web.SessionState.IReadOnlySessionState") != null)
                        this.handlersToRunWithReadOnlySession.Add(handler);
                    else
                        this.handlersToRunWithSession.Add(handler);
                }
                else
                    this.handlersToRunNoSession.Add(handler);
            }
        }
    }
}
